package Test.ThreadTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @Title: ecology-idea
 * @Company: 泛微软件
 * @author: weaver.Dusongsong
 * @version: 1.0
 * @CreateDate: 2022-09-05
 * @Description: ${description}
 * @ModifyLog:
 **/

public class ThreadDemo {
    public static void main(String[] args) {
        test01();
        test02();
        test03();
    }
   /**
   *@Description: 一般大家都会这样使用线程池，但是有没有思考过这样使用有没有什么问题？
    * 反正我发现两个比较严重的问题：
    * 获取结果时，调用的future.get()方法，会阻塞当前线程，直到返回结果，大大降低性能
    * 有一半的代码在写怎么使用线程，其实我们不应该关心怎么使用线程，更应该关注任务的处理
   *@Param: []
   *@return: void
   *@Author: Dusongsong
   *@Date: 2022/9/5
   */
    public static void test01(){
        // 1. 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        List<Integer> list = Arrays.asList(1, 2, 3);
        List<Future<String>> futures = new ArrayList<>();
        for (Integer key : list) {
            // 2. 提交任务
            Future<String> future = executorService.submit(() -> {
                // 睡眠一秒，模仿处理过程
                Thread.sleep(1000L);
                return "结果" + key;
            });
            futures.add(future);
        }

        // 3. 获取结果
        for (Future<String> future : futures) {
            try {
                String result = future.get();
                System.out.println(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        executorService.shutdown();
    }
    /**
    *@Description: 看一下使用CompletableFuture改造后代码：
    *@Param: []
    *@return: void
    *@Author: Dusongsong
    *@Date: 2022/9/5
    */
    public static void test02(){
        // 1. 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        List<Integer> list = Arrays.asList(1, 2, 3);
        for (Integer key : list) {
            // 2. 提交任务
            CompletableFuture.supplyAsync(() -> {
                // 睡眠一秒，模仿处理过程
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                }
                return "结果" + key;
            }, executorService).whenCompleteAsync((result, exception) -> {
                // 3. 获取结果
                System.out.println(result);
            });;
        }

        executorService.shutdown();
        // 由于whenCompleteAsync获取结果的方法是异步的，所以要阻塞当前线程才能输出结果
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
    *@Description: 代码中使用了CompletableFuture的两个方法，
     * supplyAsync()方法作用是提交异步任务，有两个传参，任务和自定义线程池。
     * whenCompleteAsync()方法作用是异步获取结果，也有两个传参，结果和异常信息。
     *
     * 代码经过CompletableFuture改造后，是多么的简洁优雅。
     * 提交任务也不用再关心线程池是怎么使用了，获取结果也不用再阻塞当前线程了。
     *
     * 如果你比较倔强，还想同步获取结果，可以使用whenComplete()方法，或者单独调用join()方法。
     * join()方法配合Stream流是这样用的：
    *@Param: []
    *@return: void
    *@Author: Dusongsong
    *@Date: 2022/9/5
    */
    public static void test03(){
        // 1. 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        List<Integer> list = Arrays.asList(1, 2, 3);
        // 2. 提交任务
        List<String> results = list.stream().map(key ->
                CompletableFuture.supplyAsync(() -> {
                    // 睡眠一秒，模仿处理过程
                    try {
                        Thread.sleep(1000L);
                    } catch (InterruptedException e) {
                    }
                    return "结果" + key;
                }, executorService))
                .map(CompletableFuture::join).collect( Collectors.toList());

        executorService.shutdown();
        // 3. 获取结果
        System.out.println(results);
    }
    /**
    *@Description: 如果让你实现等待所有任务线程执行完成，再进行下一步操作，你会怎么做？
     * 我猜你一定会使用 线程池+CountDownLatch
    *@Param: []
    *@return: void
    *@Author: Dusongsong
    *@Date: 2022/9/5
    */
    public static void test04(){
        // 1. 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        List<Integer> list = Arrays.asList(1, 2, 3);
        CountDownLatch countDownLatch = new CountDownLatch(list.size());
        for (Integer key : list) {
            // 2. 提交任务
            executorService.execute(() -> {
                // 睡眠一秒，模仿处理过程
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                }
                System.out.println("结果" + key);
                countDownLatch.countDown();
            });
        }

        executorService.shutdown();
        // 3. 阻塞等待所有任务执行完成
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
        }   
    }
    /**
    *@Description:
    *@Param: []
    *@return: void
    *@Author: Dusongsong
    *@Date: 2022/9/6
    */
    public static void test05(){
        
    }
}
